home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 4 / The 640 Meg Shareware Studio CD-ROM Volume IV (Data Express)(1994).ISO / clang / 120_01.zip / L2.C < prev    next >
Text File  |  1993-06-01  |  20KB  |  839 lines

  1. /* HEADER: CUG120.08;
  2.    TITLE: L2;
  3.    DATE: 00/00/1980;
  4.    DESCRIPTION: "An improved linker for .CRL format object files.
  5.     The jump table at the beginning of each function is eliminated.";
  6.    KEYWORDS: relocatable,linker;
  7.    SYSTEM: CP/M;
  8.    FILENAME: L2.C;
  9.    CRC: D3E7;
  10.    SEE-ALSO: CLINK;
  11.    AUTHORS: Scott W. Layson;
  12.    COMPILERS: BDS C;
  13. */
  14. /*     ********
  15.     * L2.C *    New linker for BDS C
  16.     ********
  17.             Written 1980 by Scott W. Layson
  18.             This code is in the public domain.
  19.  
  20.     This is an improved linker for BDS C CRL format.  It eliminates the
  21.     jump table at the beginning of each function in the object code,
  22.     thus saving up to 10% or so in code space with a slight improvement
  23.     in speed.  
  24. */
  25.  
  26.  
  27. /**************** Globals ****************/
  28.  
  29. /*    #define SDOS                /* comment this out for CP/M */*/
  30.  
  31. #define OVERLAYS            /* comment this out for shorter version */
  32.  
  33. #define MARC                /* for MARC cross-linker version 
  34.                                 (enables the "-marc" option) */
  35.  
  36. #include "bdscio.h"            /* for i/o buffer defs */
  37.  
  38. #define NUL        0
  39. #define FLAG        char
  40. #define repeat     while (1)
  41.  
  42. #define STDOUT        1
  43.  
  44. /* Phase control */
  45. #define INMEM        1        /* while everything still fits */
  46. #define DISK1        2        /* overflow; finish building table */
  47. #define DISK2        3        /* use table to do window link */
  48. int phase;
  49.  
  50.  
  51. /* function table */
  52. struct funct {
  53.     char fname[9];
  54.     FLAG flinkedp;            /* in memory already? */
  55.     char *faddr;            /* address of first ref link if not linked */
  56.     } *ftab;
  57. int nfuncts;                /* no. of functions in  table */
  58. int maxfuncts;                /* table size */
  59.  
  60. #define LINKED        1        /* (flinkedp) function really here */
  61. #define EXTERNAL    2        /* function defined in separate symbol table */
  62.  
  63. char fdir [512];            /* CRL file function directory */
  64.  
  65. /* command line parameters etc. */
  66. int nprogs, nlibs;
  67. char progfiles [30] [15];    /* program file names */
  68. char libfiles [20] [15];        /* library file names */
  69. FLAG symsp,                /* write symbols to .sym file? */
  70.     appstatsp,            /* append stats to .sym file? */
  71.     sepstatsp;            /* write stats to .lnk file? */
  72.  
  73. #ifdef MARC
  74. FLAG maxmemp,                /* punt MARC shell? */
  75.     marcp;                /* uses CM.CCC */
  76. #endif
  77.  
  78. char mainfunct[10];
  79. FLAG ovlp;                /* make overlay? */
  80. char symsfile [15];            /* file to load symbols from (for overlays) */
  81.  
  82. FLAG Tflag;                /* TRUE if "-t" option given    */
  83. unsigned Tval;                /* arg to "-t", if present    */
  84.  
  85. /* useful things to have defined */
  86. struct inst {
  87.     char opcode;
  88.     char *address;
  89.     };
  90.  
  91. union ptr {
  92.     unsigned u;            /* an int */
  93.     unsigned *w;            /* a word ptr */
  94.     char *b;                /* a byte ptr */
  95.     struct inst *i;        /* an instruction ptr */
  96.     };
  97.  
  98.  
  99. /* Link control variables */
  100.  
  101. union ptr codend;            /* last used byte of code buffer + 1 */
  102. union ptr exts;            /* start of externals */
  103. union ptr acodend;            /* actual code-end address */
  104. unsigned extspc;            /* size of externals */
  105. unsigned origin;            /* origin of code */
  106. unsigned buforg;            /* origin of code buffer */
  107. unsigned jtsaved;            /* bytes of jump table saved */
  108.  
  109. char *lspace;                /* space to link in */
  110. char *lspcend;                /* end of link area */
  111. char *lodstart;            /* beginning of current file */
  112.  
  113.  
  114. /* i/o buffer */
  115. struct iobuf {
  116.     int fd;
  117.     int isect;            /* currently buffered sector */
  118.     int nextc;            /* index of next char in buffer */
  119.     char buff [128];
  120.     } ibuf, obuf;
  121.  
  122. /* BDS C i/o buffer */
  123. char symbuf[BUFSIZ];
  124.  
  125. /* seek opcodes */
  126. #define ABSOLUTE 0
  127. #define RELATIVE 1
  128.  
  129. #define INPUT 0
  130.  
  131. #define TRUE (-1)
  132. #define FALSE 0
  133. #define NULL 0
  134.  
  135. /* 8080 instructions */
  136. #define LHLD 0x2A
  137. #define LXISP 0x31
  138. #define LXIH 0x21
  139. #define SPHL 0xF9
  140. #define JMP  0xC3
  141. #define CALL 0xCD
  142.  
  143. /* strcmp7 locals, made global for speed */
  144. char _c1, _c2, _end1, _end2;
  145.  
  146. /**************** End of Globals ****************/
  147.  
  148.  
  149. main (argc, argv)
  150.     int argc;
  151.     char **argv;
  152. {
  153.     puts ("Mark of the Unicorn Linker for BDS C, vsn. 2.2\n");
  154.     setup (argc, argv);
  155.     linkprog();
  156.     linklibs();
  157.     if (phase == DISK1) rescan();
  158.     else wrtcom();
  159.     if (symsp) wrtsyms();
  160.     }
  161.  
  162.  
  163. setup (argc, argv)            /* initialize function table, etc. */
  164.     int argc;
  165.     char **argv;
  166. {
  167.     symsp = appstatsp = sepstatsp = FALSE;    /* default options */
  168. #ifdef MARC
  169.     marcp = maxmemp = FALSE;
  170. #endif
  171.     ovlp = FALSE;
  172.     nprogs = 0;
  173.     nlibs = 0;
  174.     strcpy (&mainfunct, "MAIN");    /* default top-level function */
  175.     origin = 0x100;            /* default origin */
  176.     maxfuncts = 200;            /* default function table size */
  177.     Tflag = FALSE;                /* no "-t" given yet    */
  178.     cmdline (argc, argv);
  179.     ftab = endext();
  180.     lspace = ftab + maxfuncts;
  181.     lspcend = topofmem() - (1024 + 2100);
  182.     if (lspace > lspcend)
  183.         Fatal ("Insufficient memory to do anything at all!\n");
  184.     loadccc();
  185.     nfuncts = 0;
  186. #ifdef OVERLAYS
  187.     if (ovlp) loadsyms();
  188. #endif
  189.     intern (&mainfunct);
  190.     phase = INMEM;
  191.     buforg = origin;
  192.     jtsaved = 0;
  193.     }
  194.  
  195.  
  196. cmdline (argc, argv)        /* process command line */
  197.     int argc;
  198.     char **argv;
  199. {
  200.     int i, progp;
  201.  
  202.     if (argc == 1) {
  203.         puts ("Usage is:\n");
  204.         puts ("  l2 {program files} -l {library files} [-w | -wa | -ws]\n");
  205.         puts ("\t[-m <main_name>] [-f <maxfuncts>] [-org <addr>]");
  206.         puts (" [-t <addr>]\n");
  207. #ifdef OVERLAYS
  208.         puts ("\t[-ovl <rootname> <addr>]");
  209. #endif
  210. #ifdef MARC
  211.         puts ("\t[-marc]");
  212. #endif
  213.         exit (1);
  214.         }
  215.     progp = TRUE;
  216.     for (i=1; i < argc; ++i) {
  217.         if (argv[i][0] == '-') {
  218.             if (!strcmp (argv[i], "-F")) {
  219.                 if (++i >= argc) Fatal ("-f argument missing.\n");
  220.                 sscanf (argv[i], "%d", &maxfuncts);
  221.                 }
  222.             else if (!strcmp (argv[i], "-L")) progp = FALSE;
  223.             else if (!strcmp (argv[i], "-M")) {
  224.                 if (++i >= argc) Fatal ("-m argument missing.\n");
  225.                 strcpy (&mainfunct, argv[i]);
  226.                 }
  227. #ifdef MARC
  228.             else if (!strcmp (argv[i], "-MARC")) {
  229.                 maxmemp = TRUE;
  230.                 marcp = TRUE;
  231.                 }
  232. #endif
  233.             else if (!strcmp (argv[i], "-ORG")) {
  234.                 if (++i >= argc) Fatal ("-org argument missing.\n");
  235.                 sscanf (argv[i], "%x", &origin);
  236.                 }
  237.             else if (!strcmp (argv[i], "-T")) {
  238.                 if (++i >= argc) Fatal ("-t argument missing.\n");
  239.                 Tflag = TRUE;
  240.                 sscanf (argv[i], "%x", &Tval);
  241.                 }
  242. #ifdef OVERLAYS
  243.             else if (!strcmp (argv[i], "-OVL")) {
  244.                 ovlp = TRUE;
  245.                 if (i + 2 >= argc) Fatal ("-ovl argument missing.\n");
  246.                 strcpy (&symsfile, argv[++i]);
  247.                 sscanf (argv[++i], "%x", &origin);
  248.                 }
  249. #endif
  250.             else if (!strcmp (argv[i], "-W")) symsp = TRUE;
  251.             else if (!strcmp (argv[i], "-WA")) symsp = appstatsp = TRUE;
  252.             else if (!strcmp (argv[i], "-WS")) symsp = sepstatsp = TRUE;
  253.             else printf ("Unknown option: '%s'\n", argv[i]);
  254.             }
  255.         else {
  256.             if (progp) strcpy (&progfiles[nprogs++], argv[i]);
  257.             else strcpy (&libfiles[nlibs++], argv[i]);
  258.             }
  259.         }
  260.     if (ovlp) strcpy (&mainfunct, &progfiles[0]);
  261. #ifdef MARC
  262.     strcpy (&libfiles[nlibs++], marcp ? "DEFFM" : "DEFF");
  263.     strcpy (&libfiles[nlibs++], marcp ? "DEFF2M" : "DEFF2");
  264. #else
  265.     strcpy (&libfiles[nlibs++], "DEFF");
  266.     strcpy (&libfiles[nlibs++], "DEFF2");
  267. #endif
  268.     }
  269.  
  270.  
  271. loadccc()                    /* load C.CCC (runtime library) */
  272. {
  273.     union ptr temp;
  274.     unsigned len;
  275.  
  276.     codend.b = lspace;
  277.     if (!ovlp) {
  278. #ifdef MARC
  279.         if (copen (&ibuf, marcp ? "CM.CCC" : "C.CCC") < 0)
  280. #else
  281.         if (copen (&ibuf, "C.CCC") < 0)
  282. #endif
  283.             Fatal ("Can't open C.CCC\n");
  284.         if (cread (&ibuf, lspace, 128) < 128)    /* read a sector */
  285.             Fatal ("C.CCC: read error!\n");
  286.         temp.b = lspace + 0x17;
  287.         len = *temp.w;                        /* how long is it? */
  288.         cread (&ibuf, lspace + 128, len - 128);    /* read rest */
  289.         codend.b += len;
  290.         cclose (&ibuf);
  291.         }
  292.     else codend.i++->opcode = JMP;
  293.     }
  294.  
  295.  
  296. linkprog()                /* link in all program files */
  297. {
  298.     int i;
  299.     union ptr dirtmp;
  300.     struct funct *fnct;
  301.  
  302.     for (i=0; i<nprogs; ++i) {
  303.         makeext (&progfiles[i], "CRL");
  304.         if (copen (&ibuf, progfiles[i]) < 0) {
  305.             printf ("Can't open %s\n", progfiles[i]);
  306.             continue;
  307.             }
  308.         printf ("\n<< Loading %s >>\n", &progfiles[i]);
  309.         readprog (i==0);
  310.         for (dirtmp.b=&fdir; *dirtmp.b != 0x80;) {
  311.             fnct = intern (dirtmp.b);            /* for each module */
  312.             skip7 (&dirtmp);                    /* in directory */
  313.             if (!fnct->flinkedp)
  314.                 linkmod (fnct, lodstart + *dirtmp.w - 0x205);
  315.             else if (phase != DISK2) {
  316.                 puts ("Duplicate program function '");
  317.                 puts (&fnct->fname);
  318.                 puts ("', not linked.\n");
  319.                 }
  320.             dirtmp.w++;
  321.             }                                /* intern & link it */
  322.         cclose (&ibuf);
  323.         }
  324.     }
  325.  
  326.  
  327. linklibs()                /* link in library files */
  328. {
  329.     int ifile;
  330.  
  331.     for (ifile=0; ifile<nlibs; ++ifile) scanlib (ifile);
  332.     while (missingp()) {
  333.         puts ("Enter the name of a file to be searched: ");
  334.         gets (&libfiles[nlibs]);
  335.         scanlib (nlibs++);
  336.         }
  337.     acodend.b = codend.b - lspace + buforg;        /* save that number! */
  338.     if (!exts.b) exts.b = acodend.b;
  339.     }
  340.  
  341.  
  342. missingp()                /* are any functions missing?  print them out */
  343. {
  344.     int i, foundp;
  345.  
  346.     foundp = FALSE;
  347.     for (i=0; i<nfuncts; ++i)
  348.         if (!ftab[i].flinkedp) {
  349.             if (!foundp) puts ("*** Missing functions:\n");
  350.             puts (&ftab[i].fname);
  351.             puts ("\n");
  352.             foundp = TRUE;
  353.             }
  354.     return (foundp);
  355.     }
  356.  
  357.  
  358. rescan()                    /* perform second disk phase */
  359. {
  360.     int i;
  361.     
  362.     for (i=0; i < nfuncts; ++i)
  363.         if (ftab[i].flinkedp == LINKED) ftab[i].flinkedp = FALSE;
  364.     phase = DISK2;
  365.     buforg = origin;
  366.     puts ("\n\n**** Beginning second disk pass ****\n");
  367.     if (!ovlp) makeext (&progfiles[0], "COM");
  368.     else makeext (&progfiles[0], "OVL");
  369.     ccreat (&obuf, &progfiles[0]);
  370.     loadccc();
  371.     hackccc();
  372.     linkprog();
  373.     linklibs();
  374.     if (cwrite (&obuf, lspace, codend.b - lspace) == -1
  375.         ||  cflush (&obuf) < 0) Fatal ("Disk write error!\n");
  376.     cclose (&obuf);
  377.     stats (STDOUT);
  378.     }
  379.  
  380.  
  381.  
  382. readprog (mainp)            /* read in a program file */
  383.     FLAG mainp;
  384. {
  385.     char extp;                            /* was -e used? */
  386.     char *extstmp;
  387.     union ptr dir;
  388.     unsigned len;
  389.  
  390.     if (cread (&ibuf, &fdir, 512) < 512)            /* read directory */
  391.         Fatal ("-- read error!\n");
  392.     if (phase == INMEM  &&  mainp) {
  393.         cread (&ibuf, &extp, 1);
  394.         cread (&ibuf, &extstmp, 2);
  395.         cread (&ibuf, &extspc, 2);
  396.         if (extp) exts.b = extstmp;
  397.         else exts.b = 0;                        /* will be set later */
  398.         }
  399.     else cseek (&ibuf, 5, RELATIVE);
  400.     for (dir.b=&fdir; *dir.b != 0x80; nextd (&dir));    /* find end of dir */
  401.     ++dir.b;
  402.     len = *dir.w - 0x205;
  403.     readobj (len);
  404.     }
  405.  
  406.  
  407. readobj (len)                /* read in an object (program or lib funct) */
  408.     unsigned len;
  409. {
  410.     if (phase == DISK1  ||  codend.b + len >= lspcend) {
  411.         if (phase == INMEM) {
  412.             puts ("\n** Out of memory -- switching to disk mode **\n");
  413.             phase = DISK1;
  414.             }
  415.         if (phase == DISK2) {
  416.             if (cwrite (&obuf, lspace, codend.b - lspace) == -1)
  417.                 Fatal ("Disk write error!\n");
  418.             }
  419.         buforg += codend.b - lspace;
  420.         codend.b = lspace;
  421.         if (codend.b + len >= lspcend)
  422.             Fatal ("Module won't fit in memory at all!\n");
  423.         }
  424.     lodstart = codend.b;
  425.     if (cread (&ibuf, lodstart, len) < len) Fatal ("-- read error!\n");
  426.     }
  427.  
  428.  
  429. scanlib (ifile)
  430.     int ifile;
  431. {
  432.     int i;
  433.     union ptr dirtmp;
  434.  
  435.     makeext (&libfiles[ifile], "CRL");
  436.     if (copen (&ibuf, libfiles[ifile]) < 0) {
  437.         printf ("Can't open %s\n", libfiles[ifile]);
  438.         return;
  439.         }
  440.     printf ("\n<< Scanning %s >>\n", &libfiles[ifile]);
  441.     if (cread (&ibuf, &fdir, 512) < 512)    /* read directory */
  442.         Fatal ("-- Read error!\n");
  443.     for (i=0; i<nfuncts; ++i) {            /* scan needed functions */
  444.         if (!ftab[i].flinkedp
  445.             && (dirtmp.b = dirsearch (&ftab[i].fname))) {
  446.             readfunct (dirtmp.b);
  447.             linkmod (&ftab[i], lodstart);
  448.             }
  449.         }
  450.     cclose (&ibuf);
  451.     }
  452.  
  453.  
  454. readfunct (direntry)            /* read a function (from a library) */
  455.     union ptr direntry;
  456. {
  457.     unsigned start, len;
  458.  
  459.     skip7 (&direntry);
  460.     start = *direntry.w++;
  461.     skip7 (&direntry);
  462.     len = *direntry.w - start;
  463.     if (cseek (&ibuf, start, ABSOLUTE) < 0) Fatal (" -- read error!");
  464.     readobj (len);
  465.     }
  466.  
  467.  
  468. linkmod (fnct, modstart)            /* link in a module */
  469.     struct funct *fnct;
  470.     union ptr    modstart;                    /* loc. of module in memory */
  471.  
  472. {
  473.     union ptr temp,
  474.             jump,                    /* jump table temp */
  475.             body,                    /* loc. of function in memory */
  476.             code,                    /* loc. of code proper in mem. */
  477.             finalloc;                    /* runtime loc. of function */
  478.     unsigned flen, nrelocs, jtsiz, offset;
  479.  
  480.     fnct->flinkedp = LINKED;
  481.     if (phase != DISK2) {
  482.         finalloc.b = codend.b - lspace + buforg;
  483.         if (phase == INMEM) chase (fnct->faddr, finalloc.b);
  484.         fnct->faddr = finalloc.b;
  485.         }
  486.      else finalloc.b = fnct->faddr;
  487.     body.b = modstart.b + strlen(modstart.b) + 3; /* loc. of function body */
  488.     jump.i = body.i + (*modstart.b ? 1 : 0);
  489.     for (temp.b = modstart.b; *temp.b; skip7(&temp)) {
  490.         jump.i->address = intern (temp.b);
  491.         ++jump.i;
  492.         }
  493.     ++temp.b;
  494.     flen = *temp.w;
  495.     code.b = jump.b;
  496.     temp.b = body.b + flen;                /* loc. of reloc parameters */
  497.     nrelocs = *temp.w++;
  498.     jtsiz = code.b - body.b;
  499.     offset = code.b - codend.b;
  500.     if (phase != DISK1)
  501.         while (nrelocs--) relocate (*temp.w++, body.b, jtsiz,
  502.                                finalloc.b, offset, flen);
  503.     flen -= jtsiz;
  504.     if (phase != DISK2) jtsaved += jtsiz;
  505.     if (phase != DISK1) movmem (code.b, codend.b, flen);
  506.     codend.b += flen;
  507.     }
  508.  
  509.  
  510. relocate (param, body, jtsiz, base, offset, flen)    /* do a relocation!! */
  511.     unsigned param, jtsiz, base, offset, flen;
  512.     union ptr body;
  513. {
  514.     union ptr instr,                    /* instruction involved */
  515.             ref;                        /* jump table link */
  516.     struct funct *fnct;
  517.  
  518. /*    if (param == 1) return;                /* don't reloc jt skip */*/
  519.     instr.b = body.b + param - 1;
  520.     if (instr.i->address >= jtsiz)
  521.         instr.i->address += base - jtsiz;            /* vanilla case */
  522.     else {
  523.         ref.b = instr.i->address + body.u;
  524.         if (instr.i->opcode == LHLD) {
  525.             instr.i->opcode = LXIH;
  526.             --ref.b;
  527.             }
  528.         fnct = ref.i->address;
  529.         instr.i->address = fnct->faddr;        /* link in */
  530.         if (!fnct->flinkedp  &&  phase == INMEM)
  531.             fnct->faddr = instr.b + 1 - offset;    /* new list head */
  532.         }
  533.     }
  534.  
  535.  
  536. intern (name)                /* intern a function name in the table */
  537.     char *name;
  538. {
  539.     struct funct *fptr;
  540.  
  541.     if (*name == 0x9D) name = "MAIN";        /* Why, Leor, WHY??? */
  542.     for (fptr = &ftab[nfuncts-1]; fptr >= ftab; --fptr) 
  543.         if (!strcmp7 (name, fptr->fname)) break;
  544.     if (fptr < ftab) {
  545.         if (nfuncts >= maxfuncts)
  546.             Fatal ("Too many functions (limit is %d)!\n", maxfuncts);
  547.         fptr = &ftab[nfuncts];
  548.         strcpy7 (fptr->fname, name);
  549.         str7tont (fptr->fname);
  550.         fptr->flinkedp = FALSE;
  551.         fptr->faddr = NULL;
  552.         ++nfuncts;
  553.         }
  554.     return (fptr);
  555.     }
  556.  
  557.  
  558. dirsearch (name)            /* search directory for a function */
  559.     char *name;
  560. {
  561.     union ptr temp;
  562.  
  563.     for (temp.b = &fdir; *temp.b != 0x80; nextd (&temp))
  564.         if (!strcmp7 (name, temp.b)) return (temp.b);
  565.     return (NULL);
  566.     }
  567.  
  568.  
  569. nextd (ptrp)                /* move this pointer to the next dir entry */
  570.     union ptr *ptrp;
  571. {
  572.     skip7 (ptrp);
  573.     ++(*ptrp).w;
  574.     }
  575.  
  576.  
  577. chase (head, loc)            /* chase chain of refs to function */
  578.     union ptr head;
  579.     unsigned loc;
  580. {
  581.     union ptr temp;
  582.  
  583.     while (head.w) {
  584.         temp.w = *head.w;
  585.         *head.w = loc;
  586.         head.u = temp.u;
  587.         }
  588.     }
  589.  
  590.  
  591. wrtcom()                    /* write out com file (from in-mem link) */
  592. {
  593.     hackccc();
  594.     if (!ovlp) makeext (&progfiles[0], "COM");
  595.     else makeext (&progfiles[0], "OVL");
  596.     if (!ccreat (&obuf, &progfiles[0]) < 0
  597.         ||  cwrite (&obuf, lspace, codend.b - lspace) == -1
  598.         ||  cflush (&obuf) < 0)
  599.         Fatal ("Disk write error!\n");
  600.     cclose (&obuf);
  601.     stats (STDOUT);
  602.     }
  603.  
  604.  
  605. hackccc()                    /* store various goodies in C.CCC code */
  606. {
  607.     union ptr temp;
  608.     struct funct *fptr;
  609.  
  610.     temp.b = lspace;
  611.     fptr = intern (&mainfunct);
  612.     if (!ovlp) {
  613. #ifdef MARC
  614.         if (!marcp) {
  615. #endif
  616.               if (!Tflag) {
  617.                 temp.i->opcode = LHLD;
  618.                 temp.i->address = origin - 0x100 + 6;
  619.                 (++temp.i)->opcode = SPHL;
  620.                 }
  621.             else {
  622.                 temp.i->opcode = LXISP;
  623.                 temp.i->address = Tval;
  624.                 }
  625.             temp.b = lspace + 0xF;            /* main function address */
  626.             temp.i->address = fptr->faddr;
  627. #ifdef MARC
  628.             }
  629. #endif
  630.         temp.b = lspace + 0x15;
  631.         *temp.w++ = exts.u;
  632.         ++temp.w;
  633.         *temp.w++ = acodend.u;
  634.         *temp.w++ = exts.u + extspc;
  635.         }
  636.     else temp.i->address = fptr->faddr;        /* that's a JMP */
  637. #ifdef MARC
  638.     if (maxmemp) {
  639.         temp.b = lspace + 0x258;
  640.         temp.i->opcode = CALL;
  641.         temp.i->address = 0x50;
  642.         }
  643. #endif
  644.     }
  645.  
  646.  
  647. wrtsyms()                    /* write out symbol table */
  648. {
  649.     int i, fd, compar();
  650.     
  651.     qsort (ftab, nfuncts, sizeof(*ftab), &compar);
  652.     makeext (&progfiles[0], "SYM");
  653.     if (fcreat (&progfiles[0], &symbuf) < 0)
  654.         Fatal ("Can't create .SYM file\n");
  655.     for (i=0; i < nfuncts; ++i) {
  656.         puthex (ftab[i].faddr, &symbuf);
  657.         putc (' ', &symbuf);
  658.         fputs (&ftab[i].fname, &symbuf);
  659.         if (i % 4 == 3) fputs ("\n", &symbuf);
  660.         else {
  661.             if (strlen (&ftab[i].fname) < 3) putc ('\t', &symbuf);
  662.             putc ('\t', &symbuf);
  663.             }
  664.         }
  665.     if (i % 4) fputs ("\n", &symbuf);    
  666.     if (appstatsp) stats (&symbuf);
  667.     putc (CPMEOF, &symbuf);
  668.     fflush (&symbuf);
  669.     fclose (&symbuf);
  670.     if (sepstatsp) {
  671.         makeext (&progfiles[0], "LNK");
  672.         if (fcreat (&progfiles[0], &symbuf) < 0)
  673.             Fatal ("Can't create .LNK file\n");
  674.         stats (&symbuf);
  675.         putc (CPMEOF, &symbuf);
  676.         fflush (&symbuf);
  677.         fclose (&symbuf);
  678.         }
  679.     }
  680.  
  681.  
  682. compar (f1, f2)            /* compare two symbol table entries by name */
  683.     struct funct *f1, *f2;
  684. {
  685. /*    return (strcmp (&f1->fname, &f2->fname));    alphabetical order */
  686.     return (f1->faddr > f2->faddr);            /* memory order */
  687.     }
  688.  
  689.  
  690. #ifdef OVERLAYS
  691. loadsyms()                /* load base symbol table (for overlay) */
  692. {                        /* symbol table must be empty! */
  693.     int nread;
  694.     FLAG done;
  695.     char *c;
  696.     
  697.     makeext (&symsfile, "SYM");
  698.     if (fopen (&symsfile, &symbuf) < 0) 
  699.         Fatal ("Can't open %s.\n", &symsfile);
  700.     done = FALSE;
  701.     while (!done) {
  702.         nread = fscanf (&symbuf, "%x%s%x%s%x%s%x%s",
  703.                      &(ftab[nfuncts].faddr), &(ftab[nfuncts].fname),
  704.                      &(ftab[nfuncts+1].faddr), &(ftab[nfuncts+1].fname),
  705.                      &(ftab[nfuncts+2].faddr), &(ftab[nfuncts+2].fname),
  706.                      &(ftab[nfuncts+3].faddr), &(ftab[nfuncts+3].fname));
  707.         nread /= 2;
  708.         if (nread < 4) done = TRUE;
  709.         while (nread-- > 0) ftab[nfuncts++].flinkedp = EXTERNAL;
  710.         }
  711.     fclose (&symbuf);
  712.     }
  713. #endif
  714.  
  715.  
  716. stats (chan)                /* print statistics on chan */
  717.     int chan;
  718. {
  719.     unsigned temp, *tptr;
  720.  
  721.     tptr = 6;
  722.     fprintf (chan, "\n\nLink statistics:\n");
  723.     fprintf (chan, "  Number of functions: %d\n", nfuncts);
  724.     fprintf (chan, "  Code ends at: 0x%x\n", acodend.u);
  725.     fprintf (chan, "  Externals begin at: 0x%x\n", exts.u);
  726.     fprintf (chan, "  Externals end at: 0x%x\n", exts.u + extspc);
  727.     fprintf (chan, "  End of current TPA: 0x%x\n", *tptr);
  728.     fprintf (chan, "  Jump table bytes saved: 0x%x\n", jtsaved);
  729.     temp = lspcend;
  730.     if (phase == INMEM)
  731.         fprintf (chan,
  732.                 "  Link space remaining: %dK\n", (temp - codend.u) / 1024);
  733.     }
  734.  
  735.  
  736. makeext (fname, ext)        /* force a file extension to ext */
  737.     char *fname, *ext;
  738. {
  739.     while (*fname && (*fname != '.')) {
  740.         *fname = toupper (*fname);        /* upcase as well */
  741.         ++fname;
  742.         }
  743.     *fname++ = '.';
  744.     strcpy (fname, ext);
  745.     }
  746.  
  747.  
  748. strcmp7 (s1, s2)            /* compare two bit-7-terminated strings */
  749.     char *s1, *s2;            /* also works for non-null NUL-term strings */
  750. {
  751. /*    char c1, c2, end1, end2;        (These are now global for speed) */
  752.  
  753.     repeat {
  754.          _c1 = *s1++;
  755.         _c2 = *s2++;
  756.         _end1 = (_c1 & 0x80) | !*s1;
  757.         _end2 = (_c2 & 0x80) | !*s2;
  758.         if ((_c1 &= 0x7F) < (_c2 &= 0x7F)) return (-1);
  759.         if (_c1 > _c2  ||  (_end2  &&  !_end1)) return (1);
  760.         if (_end1  &&  !_end2) return (-1);
  761.         if (_end1  &&  _end2) return (0);
  762.         }
  763.     }
  764.  
  765.  
  766. strcpy7 (s1, s2)            /* copy s2 into s1 */
  767.     char *s1, *s2;
  768. {
  769.     do {
  770.         *s1 = *s2;
  771.         if (!*(s2+1)) {                /* works even if */
  772.             *s1 |= 0x80;                /* s2 is null-term */
  773.             break;
  774.             }
  775.         ++s1;
  776.         } while (!(*s2++ & 0x80));
  777.     }
  778.  
  779.  
  780. skip7 (ptr7)                /* move this pointer past a string */
  781.     char **ptr7;
  782. {
  783.     while (!(*(*ptr7)++ & 0x80));
  784.     }
  785.  
  786.  
  787. str7tont (s)                /* add null at end */
  788.     char *s;
  789. {
  790.     while (!(*s & 0x80)) {
  791.         if (!*s) return;        /* already nul term! */
  792.         s++;
  793.         }
  794.     *s = *s & 0x7F;
  795.     *++s = NUL;
  796.     }
  797.  
  798.  
  799. puthex (n, obuf)            /* output a hex word, with leading 0s */
  800.     unsigned n;
  801.     char *obuf;
  802. {
  803.     int i, nyb;
  804.     
  805.     for (i = 3; i >= 0; --i) {
  806.         nyb = (n >> (i * 4)) & 0xF;
  807.         nyb += (nyb > 9) ? 'A' - 10 : '0';
  808.         putc (nyb, obuf);
  809.         }
  810.     }
  811.  
  812.  
  813. Fatal (arg1, arg2, arg3, arg4)    /* lose, lose */
  814.     char *arg1, *arg2, *arg3, *arg4;
  815. {
  816.     printf (arg1, arg2, arg3, arg4);
  817.     exit (1);
  818.     }
  819.  
  820.  
  821. exit (status)                /* exit the program */
  822.     int status;
  823. {
  824.     if (status == 1) {
  825. #ifdef SDOS
  826.         unlink ("a:$$$$.cmd");
  827. #else
  828.         unlink ("a:$$$.sub");
  829. #endif
  830.         }
  831.     bios (1);                    /* bye! */
  832.     }
  833.  
  834.  
  835.  
  836. /* END OF L2.C */
  837. , "  Jump table bytes saved: 0x%x\n", jtsaved);
  838.     temp = lspcend;
  839.     if (